# 第4周作业：通过Python编程完成一个银行ATM机模拟系统，具备如下功能:
# (1)登陆验证：用户输入用户名密码登陆，检测用户名是否存在以及用户名密码是否匹配；用户名密码共有三次输入机会，超过三次系统退出。
# (2)菜单界面：登陆成功后显示功能操作界面，输入序号选择对应功能。
# (3)用户注册：用户可以输入用户名和密码创建自己的账号，并输入电话号码等信息，如果用户名存在则让用户重新输入用户名。注册后免费赠送5000元余额。
# (4)账户管理：用户可以随时查看自己的账户余额。用户可以输入其他账户用户名，实现转账功能；转账时用户名必须存在，否则提示异常。用户也可以模拟实现存取款功能。
# (5)用户名和密码以及账户信息等必须永久保存。且基于命令行完成，不需要开发GUI界面。
# ps:实现方式不限
# 第5点 这个，不需要强制完成，有能力的话，可以考虑下如何去做，提示下 open 语句或者json的dump

import logging
import bcrypt
from sqlalchemy import create_engine, Integer, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
import sqlalchemy

DATAFMT = "%Y/%m/%d-%H:%M:%S"
FORMAT = "%(lineno)d %(asctime)s %(processName)s %(process)d %(threadName)s %(thread)d   %(message)s"
logging.basicConfig(level=logging.INFO, format=FORMAT, datefmt=DATAFMT)
USERNAME = "xhm"
PASSWORD = "159180"
HOST = "192.168.206.128"
PORT = 3306
DBNAME = "User"
engine = create_engine(f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DBNAME}")  # , echo=True)
Base = declarative_base()

session = sessionmaker(bind=engine)()


class User(Base):
    __tablename__ = "User"

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(15), nullable=False, unique=True)
    password = Column(String(128), nullable=False)
    money = Column(Integer)
    phone_number = Column(Integer)

    def __repr__(self):
        return "<{} {} {} {} {}>".format(
            __class__.__name__,
            self.id,
            self.name,
            self.money,
            self.phone_number,
        )


class Atm:
    PRESENT_MONEY = 5000
    TIMES = 3

    def __init__(self, name="NB_ATM", session=None):
        self.name = name
        self.session: sqlalchemy.orm.Session = session
        self.map = {
            1: self._login,
            2: self._register,
        }
        self.sub_map = {
            0: lambda x: 0,
            1: self.show_money,
            2: self.remit_money,
            3: self.save_money,
        }

    def run(self):
        self.show()

    def _register(self):
        name = input("your name")
        query = self.query(name)
        print(query, 222222222222)
        if query:
            return
        password = input("your password")
        phone_num = input("phone number")
        ps = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode()
        info = {
            "name": name,
            "password": ps,
            "money": self.PRESENT_MONEY,
            "phone_number": phone_num,
        }
        user = User(**info)
        self.session.add(user)
        self.session.commit()
        print(f"注册成功，您的用户名为:{name}")
        return True

    def _login(self):
        name = input("your name")
        user = self.query(name)
        if user:
            for _ in range(self.TIMES):
                if self.check_password(user):  # OK
                    print("登陆成功")
                    self.login_ok(user)
                    return True

    def _admin(self):
        pass

    def show(self):
        while True:
            print(f"{'#'*20}主页面{'#'*20}")
            print(f"{'#'*20}功  能{'#'*20}")
            print(f"\t\t\t1{'-'*10}login")
            print(f"\t\t\t2{'-'*10}register")
            # print(f"{'#'*10}3{'#'*10}register")
            try:
                cmd = int(input('>>>').strip())
                self.map.get(cmd, lambda: print("不存在此选项"))()
            except Exception as e:
                print(e)

    def query(self, name):
        user = self.session.query(User).filter(User.name.ilike(name))
        print('~' * 50)
        return user.first()

    def check_password(self, user):
        password = input("your password").encode()
        print(user, "==============")
        if bcrypt.checkpw(password, user.password.encode()):
            return True

    def login_ok(self, user):
        cmd = None
        while cmd != 0:
            print(f"{'#'*20}个人页面{'#'*20}")
            print(f"{'#'*20}功  能{'#'*20}")
            print(f"\t\t\t0{'-'*10}logout")
            print(f"\t\t\t1{'-'*10}show money")
            print(f"\t\t\t2{'-'*10}remit money")
            print(f"\t\t\t3{'-'*10}save_money")
            cmd = int(input('>>>').strip())
            try:
                self.sub_map.get(cmd, lambda x: print("不存在此选项"))(user)
            except Exception as e:
                print(e)

    def show_money(self, user):
        print("your money -->", user.money)
        return user.money

    def remit_money(self, user):
        name = input("His/Her name")
        if name == user.name:
            print("你不能给自己打钱")
            return
        r_user = self.query(name)
        if r_user:
            old_money = self.show_money(user)
            money = int(input("want to remit money").strip())
            if old_money < money:
                print("你钱没那么多")
            else:
                r_user.money += money
                user.money -= money
                self.session.add(r_user)
                self.session.add(user)
                self.session.commit()
            self.show_money(user)
        else:
            print("没有这个人")

    def save_money(self, user):
        money = int(input("你要存多少钱？").strip())
        if money > 0:
            user.money += money
            self.session.add(user)
            self.session.commit()
        self.show_money(user)


atm = Atm(session=session)
atm.run()


# 可以啊，什么数据库和 loggging ，orm 都用上了